﻿#include "as_mmap.h"
#include <iostream>
#include <fstream>
#include "time_value.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#endif

as::tools::GameMMap::GameMMap()
{

}

as::tools::GameMMap::~GameMMap()
{
#ifdef _WIN32
	// 此处可以使用共享内存 pBuf
	if(pBuf)
		UnmapViewOfFile(pBuf);
	if(hMapFile)
		CloseHandle(hMapFile);
#else
	if(pBuf)
		::munmap((void*)pBuf, 256);
	if(filePath.empty() == false)
		::shm_unlink(filePath.c_str());
#endif
}

bool as::tools::GameMMap::CreateMMap(const char *file_path, int size)
{

#ifdef _WIN32
	TimeValue t;
	hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, file_path);
	if (hMapFile)
	{
		// 将共享内存映射到进程地址空间中
		pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
		if (pBuf == NULL) {
			std::cerr << "Could not map view of file: " << GetLastError() << std::endl;
			CloseHandle(hMapFile);
			return false;
		}

		//std::cout << "内存对象映射返回内存:" << file_path << " cost:" << t.dif() << std::endl;
		return false;
	}

	hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE,    // 物理文件句柄
		NULL,                    // 默认安全级别
		PAGE_READWRITE,          // 可读写访问权限
		0,                       // 文件映射对象的大小（高位）
		size,                     // 文件映射对象的大小（低位）
		file_path	  // 文件映射对象名称
	);
	if (hMapFile == NULL) {
		std::cerr << "Could not create file mapping object: " << GetLastError() << std::endl;
		return false;
	}

	pBuf = (LPTSTR)MapViewOfFile(
		hMapFile,                // 文件映射对象的句柄
		FILE_MAP_READ | FILE_MAP_WRITE,     // 可读写访问权限
		0,
		0,
		size);

	if (pBuf == NULL) {
		std::cerr << "Could not map view of file: " << GetLastError() << std::endl;

		CloseHandle(hMapFile);
		return false;
	}

	//std::cout << "内存对象映射第一次返回内存:" << file_path << " cost:" << t.dif() << std::endl;
#endif
	return true;
}

const char* as::tools::GameMMap::CreateFileMMap(const char *file_path)
{
	std::string str = file_path;
	str.append(".mmap");

#ifdef _WIN32
	TimeValue t;
	hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, str.c_str());
	if (hMapFile)
	{
		// 将共享内存映射到进程地址空间中
		pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
		if (pBuf == NULL) {
			std::cerr << "Could not map view of file: " << GetLastError() << std::endl;
			CloseHandle(hMapFile);
			return nullptr;
		}

		//std::cout << "内存文件映射返回内存:" << file_path << " cost:" << t.dif() << std::endl;
		return pBuf;
	}

	// 打开文件
	HANDLE hFile = CreateFile(file_path, GENERIC_READ | GENERIC_WRITE, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		std::cerr << "Failed to open file:" << GetLastError() << std::endl;
		return nullptr;
	}

	// 获取文件大小
	DWORD dwFileSize = GetFileSize(hFile, NULL);

	hMapFile = CreateFileMapping(
		hFile,    // 物理文件句柄
		NULL,                    // 默认安全级别
		PAGE_READWRITE,          // 可读写访问权限
		0,                       // 文件映射对象的大小（高位）
		dwFileSize,                     // 文件映射对象的大小（低位）
		str.c_str()	  // 文件映射对象名称
	);
	if (hMapFile == NULL) {
		std::cerr << "Could not create file mapping object: " << GetLastError() << std::endl;
		return nullptr;
	}

	pBuf = (LPTSTR)MapViewOfFile(
		hMapFile,                // 文件映射对象的句柄
		FILE_MAP_READ | FILE_MAP_WRITE,     // 可读写访问权限
		0,
		0,
		dwFileSize);

	CloseHandle(hFile);

	if (pBuf == NULL) {
		std::cerr << "Could not map view of file: " << GetLastError() << std::endl;

		CloseHandle(hMapFile);
		return nullptr;
	}

	//std::cout << "内存文件映射第一次返回内存:" << file_path << " cost:" << t.dif() << std::endl;
#else

	filePath = str;
	hMapFile = shm_open(str.c_str(), O_RDWR, 0666);
	if (hMapFile == -1) 
	{
			// 打开文件
		std::ifstream file(file_path);
		if (!file.is_open()) {
			std::cerr << "Failed to open file" << std::endl;
			return nullptr;
		}

		// 获取文件大小
		file.seekg(0, std::ios::end);
		int file_size = file.tellg();
		file.seekg(0, std::ios::beg);
		
		hMapFile = shm_open(str.c_str(), O_CREAT | O_RDWR, 0666);
		if (hMapFile == -1)
		{
			file.close();
			return nullptr;
		}
		
		// 设置共享内存大小
		ftruncate(hMapFile, file_size);

		// 将共享内存映射到进程地址空间中
		pBuf = (const char*)mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, hMapFile, 0);
		if (pBuf == MAP_FAILED) {
			std::cerr << "Failed to map shared memory" << std::endl;
			return pBuf;
		}
	}

	struct stat s;
	fstat(hMapFile, &s);
	int file_size = s.st_size;

	ftruncate(hMapFile, file_size); // 设置共享内存大小

	pBuf = (const char *)mmap(nullptr, 256, PROT_READ | PROT_WRITE, MAP_SHARED, hMapFile, 0);
	if (pBuf == MAP_FAILED) {
		std::cerr << "Failed to map shared memory" << std::endl;
		return nullptr;
	}
#endif

	return pBuf;
}

const char *as::tools::GameMMap::get_buf()
{
	return pBuf;
}
